﻿using System;
using System.Collections;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using DoNet.Utils;

namespace DoNet.TenPay
{
    public class SignatureV2
    {
        public const string SIGN_TYPE_MD5 = "MD5";
        public const string SIGN_TYPE_SHA1 = "SHA1";
        public const string SIGN_TYPE_HMAC_SHA256 = "HMAC-SHA256";

        /// <summary>
        /// 生成签名，详见签名生成算法
        /// </summary>
        /// <param name="signType"></param>
        /// <returns>签名, sign字段不参加签名</returns>
        public static string MakeSign(Hashtable hashtable, string signType, string key)
        {
            string strSign = "";
            //转url格式
            string str = ToUrl(hashtable);

            //在string后加入API KEY
            str += "&key=" + key;
            if (signType == SIGN_TYPE_MD5)
            {
                strSign = SignHelper.CalMd5(str);
            }
            else if(signType == SIGN_TYPE_SHA1)
            {
                strSign = SignHelper.CalSHA1(str);
            }
            else if (signType == SIGN_TYPE_HMAC_SHA256)
            {
                strSign = SignHelper.CalcHMACSHA256Hash(str, key);
            }
            else
            {
                //throw new WxPayException("sign_type 不合法");
            }
            return strSign;
        }

        /// <summary>
        /// 检测签名是否正确
        /// </summary>
        /// <param name="signType"></param>
        /// <returns>正确返回true，错误返回false</returns>
        public static bool CheckSign(Hashtable hashtable, string signType, string key)
        {
            bool isSign = false;
            //如果没有设置签名，则跳过检测
            if (hashtable.ContainsKey("sign"))
            {
                //如果设置了签名但是签名为空，则抛异常
                if (hashtable["sign"] != null && hashtable["sign"].ToString() != "")
                {
                    //获取接收到的签名
                    string return_sign = hashtable["sign"].ToString();

                    //在本地计算新的签名
                    string cal_sign = MakeSign(hashtable, signType, key);

                    if (cal_sign == return_sign)
                    {
                        isSign = true;
                    }
                    else
                    {
                        //throw new WxPayException("WxPayData签名验证错误!");
                    }
                }
                else
                {
                    //throw new WxPayException("WxPayData签名存在但不合法!");
                }
            }
            else
            {
                //throw new WxPayException("WxPayData签名存在但不合法!");
            }
            return isSign;
        }
        /// <summary>
        /// Dictionary格式转化成url参数格式
        /// </summary>
        /// <returns>url格式串, 该串不包含sign字段值</returns>
        public static string ToUrl(Hashtable hashtable)
        {
            string buff = "";
            //遍历方法一：遍历哈希表中的键
            foreach (string key in hashtable.Keys)
            {
                if (hashtable[key] != null)
                {
                    if (key != "sign" && hashtable[key].ToString() != "")
                    {
                        buff += key + "=" + hashtable[key] + "&";
                    }
                }
            }
            buff = buff.Trim('&');
            return buff;
        }

        /// <summary>
        /// 将Dictionary转成xml
        /// </summary>
        /// <returns>经转换得到的xml串</returns>
        public static string ToXml(Hashtable hashtable)
        {
            //数据为空时不能转化为xml格式
            string xml = "";
            if (hashtable.Count > 0)
            {
                xml += "<xml>";
                foreach (string key in hashtable.Keys)
                {
                    //字段值不能为null，会影响后续流程
                    if (hashtable[key] != null)
                    {
                        if (hashtable[key].GetType() == typeof(int))
                        {
                            xml += "<" + key + ">" + hashtable[key] + "</" + key + ">";
                        }
                        else if (hashtable[key].GetType() == typeof(string))
                        {
                            xml += "<" + key + ">" + "<![CDATA[" + hashtable[key] + "]]></" + key + ">";
                        }
                        else//除了string和int类型不能含有其他数据类型
                        {
                            //throw new WxPayException("WxPayData字段数据类型错误!");
                        }
                    }
                    else
                    {
                        //throw new WxPayException("WxPayData内部含有值为null的字段!");
                    }
                }
                xml += "</xml>";
            }
            else
            {
                //throw new WxPayException("WxPayData数据为空!");
            }
            return xml;
        }

        /// <summary>
        /// C# Hashtable转object实体对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static T HashtableToObject<T>(Hashtable source)
        {
            T obj = Activator.CreateInstance<T>();
            object tv;

            PropertyInfo[] ps = obj.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            foreach (PropertyInfo p in ps)
            {
                if (source.ContainsKey(p.Name))
                {
                    tv = source[p.Name];
                    if (p.PropertyType.IsArray)//数组类型,单独处理
                    {
                        p.SetValue(obj, tv, null);
                    }
                    else
                    {
                        if (String.IsNullOrEmpty(tv.ToString()))//空值
                            tv = p.PropertyType.IsValueType ? Activator.CreateInstance(p.PropertyType) : null;//值类型
                        else
                            tv = System.ComponentModel.TypeDescriptor.GetConverter(p.PropertyType).ConvertFromString(tv.ToString());//创建对象

                        p.SetValue(obj, tv, null);
                    }
                }
            }
            return obj;
        }

        /// <summary>
        /// C# 实体对象Object转HashTable
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Hashtable ObjectToHashtable(object obj)
        {
            Hashtable hash = new Hashtable();
            PropertyInfo[] ps = obj.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            foreach (PropertyInfo p in ps)
            {
                hash.Add(p.Name, p.GetValue(obj));
            }
            return hash;
        }

        /// <summary>
        /// 退款解密 AES-256-ECB字符解密
        /// </summary>
        /// <param name="req_info">退款接口返回的 加密信息req_info</param>
        /// <param name="keyMd5">MD5后的密钥</param>
        /// <returns></returns>
        public static string DecodeAES256ECB(string req_info, string keyMd5)
        {
            string decode = null;
            try
            {
                byte[] keyArray = UTF8Encoding.UTF8.GetBytes(keyMd5);
                byte[] toEncryptArray = Convert.FromBase64String(req_info);
                using (RijndaelManaged rDel = new RijndaelManaged())
                {
                    rDel.Key = keyArray;
                    rDel.Mode = CipherMode.ECB;
                    rDel.Padding = PaddingMode.PKCS7;
                    using (ICryptoTransform cTransform = rDel.CreateDecryptor())
                    {
                        byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
                        decode = UTF8Encoding.UTF8.GetString(resultArray);
                    }
                }
            }
            catch { }
            return decode;
        }
    }
}
